package com.zh.mediaservice.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.Config;
import com.alipay.easysdk.payment.facetoface.models.AlipayTradePrecreateResponse;

import com.zh.mediacommon.constant.AliPayConstant;
import com.zh.mediacommon.constant.ReserveConstant;
import com.zh.mediacommon.ecxeption.AliPayException;
import com.zh.mediacommon.util.OrderUtil;
import com.zh.mediacommon.util.QRCodeUtil;
import com.zh.mediapojo.dto.OrderDTO;
import com.zh.mediapojo.entity.Order;

import com.zh.mediapojo.vo.AlipayVO;
import com.zh.mediapojo.vo.PayNotPayOrderVO;
import com.zh.mediapojo.vo.ReserveOrderVO;
import com.zh.mediaservice.mapper.OrderMapper;
import com.zh.mediaservice.service.OrderService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.servlet.http.HttpServletRequest;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Semaphore;

@Service
@Slf4j
@AllArgsConstructor
public class OrderServiceImpl implements OrderService {
    @Autowired
    private OrderMapper orderMapper;
    private final Config config;
    @Autowired
    private RedisTemplate redisTemplate;

    private final static Map<String, Semaphore > semaphoreMap = new ConcurrentHashMap<>();
    @Override
    @Transactional
    public AlipayVO createOrder(OrderDTO orderDTO) {
       Integer default_num=orderDTO.getReserveTime().equals("上午")?ReserveConstant.DEFAULT_MAX_NUM_AM:ReserveConstant.DEFAULT_MAX_NUM_PM;
        Semaphore semaphore = semaphoreMap.computeIfAbsent(
                orderDTO.getDoctorId().toString()+"_"+orderDTO.getReserveTime(),
                k->new Semaphore(default_num)
        );

       try{
           if(semaphore.tryAcquire()){
               Factory.setOptions(config);
               List<Order> orderList = orderMapper.selectOrderByUid(orderDTO.getUid());

               //判断是否有未支付的订单
               if(orderList.size()>0) {
                   log.info("orderList{}",orderList);
                   throw new AliPayException(AliPayConstant.HAVA_ORDER_NOT_PAY);
               }
               try {
                   log.info("支付宝创建订单");
                   String orderId = OrderUtil.generateOrderId();
                   //将数据插入数据库
                   Order order = new Order();
                   BeanUtils.copyProperties(orderDTO,order);
                   order.setOrderId(orderId);
                   order.setCreateTime(LocalDateTime.now());
                   orderMapper.insert(order);

                   HashOperations hashOperations = redisTemplate.opsForHash();
                   hashOperations.put(orderId,"doctorId",orderDTO.getDoctorId());
                   if(orderDTO.getReserveTime().equals("上午")) {
                       Integer maxnum = (Integer) hashOperations.get(orderDTO.getDoctorId().toString(), ReserveConstant.MAX_NUM_AM);
                       Integer nowNum = (Integer) hashOperations.get(orderDTO.getDoctorId().toString(), ReserveConstant.NOW_NUM_AM);
                       if(nowNum>=maxnum)
                           throw new AliPayException(AliPayConstant.MAX_NUM);
                       hashOperations.put(orderId, "time", ReserveConstant.NOW_NUM_AM);
                   }
                   else {
                       Integer maxnum = (Integer) hashOperations.get(orderDTO.getDoctorId().toString(), ReserveConstant.MAX_NUM_PM);
                       Integer nowNum = (Integer) hashOperations.get(orderDTO.getDoctorId().toString(), ReserveConstant.NOW_NUM_PM);
                       if(nowNum>=maxnum)
                           throw new AliPayException(AliPayConstant.MAX_NUM);
                       hashOperations.put(orderId, "time", ReserveConstant.NOW_NUM_PM);
                   }
                   AlipayTradePrecreateResponse alipayTradePrecreateResponse = Factory.Payment.FaceToFace().preCreate(OrderUtil.getSubject(),
                           orderId, orderDTO.getPrice().toString());
                   String httpBody = alipayTradePrecreateResponse.getHttpBody();
                   JSONObject json = JSONObject.parseObject(httpBody);
                   String qrUrl = json.getJSONObject("alipay_trade_precreate_response").get("qr_code").toString();
                   //生成二维码
                   String qrCode = QRCodeUtil.generateQRCode(qrUrl, 300, 300);
                   AlipayVO alipayVO = new AlipayVO(orderId, qrCode);
                   String key=orderDTO.getReserveTime().equals("上午")?ReserveConstant.NOW_NUM_AM:ReserveConstant.NOW_NUM_PM;
                  //将订单转为预支付状态
                   Integer num = (Integer) hashOperations.get(orderDTO.getDoctorId().toString(), key);
                   if(num==null)
                       num=0;
                   num+=1;
                   hashOperations.put(orderDTO.getDoctorId().toString(),key,num);
                   return alipayVO;
               } catch (Exception e) {
                   log.info("支付宝创建订单失败{}",e.getMessage());
                   throw new AliPayException(AliPayConstant.ALIPAY_ERROR);
               }
           }else {
               log.info("未获取许可");
               throw new AliPayException(AliPayConstant.REQUEST_CROWDED);
           }
       }catch (Exception e){
            log.info("错误原因,{}",e.getMessage());
            throw new AliPayException(e.getMessage());
       }finally {
           semaphore.release();
       }
    }

    @Override
    public void notifyOrder(HttpServletRequest request) {
        if (request.getParameter("trade_status").equals("TRADE_SUCCESS")){
            log.info("=========支付宝异步回调========");
            Map<String, String> params = new HashMap<>();
            Map<String, String[]> requestParams = request.getParameterMap();
            requestParams.forEach((k, v) -> params.put(k, v[0]));
            String tradeNo = params.get("out_trade_no");
            orderMapper.updateOrderStatus(tradeNo);
        }
    }

    @Override
    public void selectOrderStatus(String outTradeNo) {
        log.info("查询订单状态{}",outTradeNo);
        String s = orderMapper.selectOrderStatus(outTradeNo);
        log.info("订单状态{}",s);
        if("0".equals(s))
            throw new AliPayException(AliPayConstant.ORDER_NOT_PAY);
        HashOperations hashOperations = redisTemplate.opsForHash();
        Integer id = (Integer) hashOperations.get(outTradeNo, "doctorId");
        String time=(String) hashOperations.get(outTradeNo, "time");
        String key="";
        if(time.equals(ReserveConstant.NOW_NUM_AM)){
            key="上午";
        }else{
            key="下午";
        }
//        Integer num = (Integer) hashOperations.get(id.toString(), time);
//        if(num == null){
//            num=new Integer(0);
//        }
//        num+=1;
//        hashOperations.put(id.toString(), time, num);
        redisTemplate.delete(outTradeNo);
        adjustConcurrency(id,key);
    }

    @Override
    public List<ReserveOrderVO> getUserOrder(Long userId) {
        List<ReserveOrderVO> orders = orderMapper.selectOrderInfo(userId);
        return orders;
    }
    @Override
    public void adjustConcurrency(Integer doctorId,String reserveTime){
        if(reserveTime.equals("上午")){
            Integer nowNum = (Integer) redisTemplate.opsForHash().get(doctorId.toString(), ReserveConstant.NOW_NUM_AM);
            Integer maxNum = (Integer) redisTemplate.opsForHash().get(doctorId.toString(), ReserveConstant.MAX_NUM_AM);
            log.info("当前人数{}",nowNum);
            log.info("最大人数{}",maxNum);
            if(nowNum>=maxNum){
                semaphoreMap.computeIfAbsent(
                        doctorId.toString()+"_"+reserveTime,k->new Semaphore(0));
            }else {
                semaphoreMap.computeIfAbsent(
                        doctorId.toString()+"_"+reserveTime,k->new Semaphore(maxNum-nowNum));
            }
        }else{
            Integer nowNum = (Integer) redisTemplate.opsForHash().get(doctorId.toString(), ReserveConstant.NOW_NUM_PM);
            Integer maxNum = (Integer) redisTemplate.opsForHash().get(doctorId.toString(), ReserveConstant.MAX_NUM_PM);
            log.info("当前人数{}",nowNum);
            log.info("最大人数{}",maxNum);
            if(nowNum>=maxNum){
                semaphoreMap.putIfAbsent(doctorId.toString()+'_'+reserveTime,new Semaphore(0));
            }else {
                semaphoreMap.putIfAbsent(
                        doctorId.toString()+"_"+reserveTime,new Semaphore(maxNum-nowNum));
            }
        }
    }
    public AlipayVO payNotPayOrder(Long id){
        log.info("开始支付未支付订单{}",id);
        PayNotPayOrderVO order=orderMapper.selectOrder(id);
        if(order==null)
            throw new AliPayException(AliPayConstant.ORDER_NOT_EXIST);
        String orderId = OrderUtil.generateOrderId();
        try {
            Factory.setOptions(config);
            AlipayTradePrecreateResponse alipayTradePrecreateResponse = Factory.Payment.FaceToFace().preCreate(OrderUtil.getSubject(),
                    orderId,order.getPrice().toString());
            String httpBody = alipayTradePrecreateResponse.getHttpBody();
            JSONObject json = JSONObject.parseObject(httpBody);
            String qrUrl = json.getJSONObject("alipay_trade_precreate_response").get("qr_code").toString();
            //生成二维码
            String qrCode = QRCodeUtil.generateQRCode(qrUrl, 300, 300);
            AlipayVO alipayVO = new AlipayVO(orderId, qrCode);
            HashOperations hashOperations = redisTemplate.opsForHash();
            hashOperations.put(orderId,"doctorId",order.getDoctorId());
            if (order.getReserveTime().equals("上午"))
                hashOperations.put(orderId, "time", ReserveConstant.NOW_NUM_AM);
            else
                hashOperations.put(orderId, "time", ReserveConstant.NOW_NUM_PM);
            orderMapper.updateOrderId(id,orderId);
            log.info("订单生成成功{}",orderId);
            return alipayVO;
        } catch (Exception e) {
            log.info("支付宝创建订单失败{}",e.getMessage());
            throw new AliPayException(AliPayConstant.ALIPAY_ERROR);
        }
    }
}
